/* Generic command (Used by FatFs) */
#define CTRL_SYNC			0	/* Complete pending write process (needed at FF_FS_READONLY == 0) */
#define GET_SECTOR_COUNT	1	/* Get media size (needed at FF_USE_MKFS == 1) */
#define GET_SECTOR_SIZE		2	/* Get sector size (needed at FF_MAX_SS != FF_MIN_SS) */
#define GET_BLOCK_SIZE		3	/* Get erase block size (needed at FF_USE_MKFS == 1) */
#define CTRL_TRIM			4	/* Inform device that the data on the block of sectors is no longer used (needed at FF_USE_TRIM == 1) */

#define SECTOR_NUM 200

/**
 * @brief The simulated disk sectors
 * each sector has 512 Bytes.
 */
// static char sectors[SECTOR_NUM][512]; //100K sectors
static char * sec_start;
static unsigned sec_count;

int ram_disk_initialize()
{

    return 0;
}

/**
 * @brief read ram disk sectors
 *
 * @param buff buffer to save content in sectors
 * @param sector start sector number
 * @param count number of sectors to be read
 * @return int 0 if success status number if failed
 */
int ram_disk_read(unsigned char *buff, unsigned sector, unsigned count)
{
    if (sector < sec_count)
    {
        for (int i = sector; i < sector + count; i++)
            for (int j = 0; j < 512; j++)
            {
                *(buff++) = *(sec_start + i*512 + j);
            }
    }
    else
    {
        return -1;
    }
    return 0;
}


/**
 * @brief write ram disk sectors
 *
 * @param buff buffer to save content in sectors
 * @param sector start sector number
 * @param count number of sectors to be read
 * @return int 0 if success status number if failed
 */
int ram_disk_write(const unsigned char *buff, unsigned sector, unsigned count)
{
    if (sector < sec_count - count)
    {
        for (int i = sector; i < sector + count; i++)
            for (int j = 0; j < 512; j++)
            {
                *(sec_start + i*512 + j) = *(buff++);
            }
    }
    else
    {
        return -1;
    }
    return 0;
}

/**
 * @brief ram disk status
 *
 * @return int status
 */
int ram_disk_status () {
    return 0;
}

int ram_disk_ioctl(unsigned char cmd, void *buff)
{
    /**
    The following comments is referenced from [ fatfs/documents/doc/dioctl.html ]
    Command	Description
    CTRL_SYNC	        Makes sure that the device has finished pending write process.
                        If the disk I/O layer or storage device has a write-back cache,
                        the dirty cache data must be committed to the medium immediately.
                        Nothing to do for this command if each write operation to the medium
                        is completed in the disk_write function.
    GET_SECTOR_COUNT	Retrieves number of available sectors, the largest allowable LBA + 1,
                        on the drive into the LBA_t variable that pointed by buff.
                        This command is used by f_mkfs and f_fdisk function to determine
                        the size of volume/partition to be created.
    GET_SECTOR_SIZE	    Retrieves sector size, minimum data unit for generic read/write,
                        into the WORD variable that pointed by buff. Valid sector sizes are 512, 1024, 2048 and 4096.
                        This command is required only if FF_MAX_SS > FF_MIN_SS. When FF_MAX_SS == FF_MIN_SS,
                        this command will never be used and the disk_read and disk_write function must work in FF_MAX_SS bytes/sector.
    GET_BLOCK_SIZE	    Retrieves erase block size in unit of sector of the flash memory media into the DWORD variable that pointed by buff.
                        The allowable value is 1 to 32768 in power of 2. Return 1 if it is unknown or in non flash memory media.
                        This command is used by f_mkfs function with block size not specified and it attempts to
                        align the data area on the suggested block boundary. Note that FatFs does not have
                        FTL (flash translation layer), so that either disk I/O layter or storage device must have an FTL in it.
    CTRL_TRIM	        Informs the disk I/O layter or the storage device that the data on the block of sectors
                        is no longer needed and it can be erased. The sector block is specified in an LBA_t
                        array {<Start LBA>, <End LBA>} that pointed by buff. This is an identical command to Trim of ATA device.
                        Nothing to do for this command if this funcion is not supported or not a flash memory device.
                        FatFs does not check the result code and the file function is not affected even if the sector block was
                        not erased well. This command is called on remove a cluster chain and in the f_mkfs function.
                        It is required when FF_USE_TRIM == 1.
    */

    // Process of the command for the ram drive
    switch (cmd)
    {
    case GET_SECTOR_COUNT:
        *(unsigned *)buff = sec_count;
        break;

    case GET_SECTOR_SIZE:
        *(unsigned *)buff = 512;
        break;

    case GET_BLOCK_SIZE:
        *(unsigned *)buff = 512;
        break;
    case CTRL_SYNC:
        break;
    case CTRL_TRIM:
        break;
    default:
        return -1;
    }
    return 0;
}
